# -*- coding: utf-8 -*-
#
#    Copyright (C) 2012 Gonzalo Bonigo <gonzalobonigo@gmail.com>
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see http://www.gnu.org/licenses/
#


"""En este modulo se definen las funciones de parseo utilizadas por daddy."""


import random
import sys
import os

from lts import utils
import lts


class ParserError (Exception):
    """
    Clase de excepcion del parser.
    """
    pass


def parse (args_list, minargs, maxargs):
    """
    Descripcion:
        Funcion encargada de parsear los argumentos de entrada.
    Argumentos:
        args_list  -  Lista de argumentos. Debe ser la lista de argumentos
                      recibida en el modulo "__main__" sin el primer
                      elemento (nombre del archivo ejecutado), es deicir,
                      solo los argumentos del programa.
        minargs    -  Es un numero el cual indica la cantidad minima de
                      argumentos que deben ser especificados.
        maxargs    -  Es un numero el cual indica la cantidad maxima de
                      argumentos que deben ser especificados.
    Retorno:
        Una instancia de la clase dict con la siguiente estructura.
        Las claves son cadenas de caracteres.
            "system"           ->  Lista de instancias de la clase LTS().
            "fault_set"        ->  Conjunto de fallas.
            "sync_set"         ->  Conjunto de eventos de sincronizacion.
            "graphic"          ->  Booleano.
            "heuristic_level"  ->  Entero entre 0 y 5.
            "time"             ->  Booleano.
            "verbose"          ->  Booleano.
            "help"             ->  Booleano.
            "mode"             ->  Entero entre 0 y 2.
    """
    # Chequeo la cantidad de argumentos ingresados.
    if len(args_list) < minargs or len(args_list) > maxargs:
        raise ParserError("The number of arguments is incorrect!")
    if len(args_list) == 1 and not '-help' in args_list:
        raise ParserError("The number of arguments is incorrect!")
    if len(args_list) > 1 and '-help' in args_list:
        raise ParserError("The number of arguments is incorrect!")
    # Valor de retorno.
    result = dict()
    result["system"] = []
    result["fault_set"] = set([])
    result["sync_set"] = set([])
    result["graphic"] = False
    result["heuristic_level"] = 0
    result["time"] = False
    result["verbose"] = False
    result["help"] = False
    result["mode"] = 0
    # Recorro la lista de argumentos.
    for arg in args_list:
        if arg.startswith("-s="):
            for s in ((arg.split('='))[1]).split(','):
                if not s:
                    raise ParserError("The argument '-s' can not be empty.")
                try:
                    result["system"].append(lts.LTS.from_file(s))
                except lts.LTSError, (msg,e):
                    errmsg = "Error in subsystem: "+str(s)+' - '+msg+' '+e
                    raise ParserError(errmsg)
        elif arg.startswith("-f="):
            f_list = ((arg.split('='))[1]).split(',')
            if not f_list or not f_list[0]:
                result["fault_set"] = None
            else:
                for f in f_list:
                    if not f.startswith('f'):
                        raise ParserError("Incorrect fault name: " + f)
                    else:
                        result["fault_set"].add(f)
        elif arg.startswith("-c="):
            for e in ((arg.split('='))[1]).split(','):
                if e and not e.startswith('c') and not e.startswith('o'):
                    errmsg = "Incorrect synchronization event name: " + e
                    raise ParserError(errmsg)
                elif e:
                    result["sync_set"].add(e)
        elif arg.startswith("-h="):
            try:
                result["heuristic_level"] = int((arg.split('='))[1])
            except ValueError:
                raise ParserError("Invalid value for arguement '-h'.")
            if result["heuristic_level"] < 0 or result["heuristic_level"] > 6:
                raise ParserError("Values for '-h' go from 0 to 6.")
        elif arg.startswith("-m="):
            try:
                result["mode"] = int((arg.split('='))[1])
            except ValueError:
                raise ParserError("Invalid value for arguement '-m'.")
            if result["mode"] < 0 or result["mode"] > 2:
                raise ParserError("Values for '-m' are 0|1|2.")
        elif arg == "-g":
                result["graphic"] = True
        elif arg == "-t":
            result["time"] = True
        elif arg == "-v":
            result["verbose"] = True
        elif arg == "-help":
            result["help"] = True
        else:
            raise ParserError("Invalid argument: " + arg)
    return result
